/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#ifndef INCLUDE_SHADER_NOISE
#define INCLUDE_SHADER_NOISE

#include "shader_built_in_functions.h"


#ifdef __cplusplus

#include <向量.h>

// GLSL Type
using uint = unsigned int;
#define in
#define out
#define inout

#else

#define Inline



#endif




Inline float f_glsl_simplexNoise(in vec2 uv) {
	//transform from triangle to quad
	const float K1 = 0.366025404; // (sqrt(3)-1)/2;
	//transform from quad to triangle
	const float K2 = 0.211324865; // (3 - sqrt(3))/6;

	//Find the rectangle vertex
	vec2  quadIntPos = floor(uv + (uv.x + uv.y) * K1);
	//relative coorindates from origin vertex A
	vec2  vecFromA = uv - quadIntPos + (quadIntPos.x + quadIntPos.y) * K2;
	float IsLeftHalf = step(vecFromA.y, vecFromA.x);
	vec2  quadVertexOffset;
	quadVertexOffset.x = IsLeftHalf;
	quadVertexOffset.y = 1.0f - IsLeftHalf;

	//vecFromA - (quadVertexOffset + (quadVertexOffset.x + quadVertexOffset.y ) * K2)
	vec2  vecFromB = vecFromA - quadVertexOffset + K2;
	//vecFromA - (vec(1, 1) + (1 + 1 ) * K2)
	vec2  vecFromC = vecFromA - 1.0 + 2.0 * K2;

	vec3 dxyz;
	dxyz.x = dot(vecFromA, vecFromA);
	dxyz.y = dot(vecFromB, vecFromB);
	dxyz.z = dot(vecFromC, vecFromC);

	vec3  falloff;
	falloff.x = 0.5 - dxyz.x;
	falloff.y = 0.5 - dxyz.y;
	falloff.z = 0.5 - dxyz.z;

	vec3 Zero;
	Zero.x = 0;
	Zero.y = 0;
	Zero.z = 0;
	falloff = max(falloff, Zero);

	vec2 ga = random(quadIntPos + 0.0);
	vec2 gb = random(quadIntPos + quadVertexOffset);
	vec2 gc = random(quadIntPos + 1.0);

	vec3 gradient;
	gradient.x = dot(vecFromA, ga);
	gradient.y = dot(vecFromB, gb);
	gradient.z = dot(vecFromC, gc);
	
	vec3 n = falloff * falloff * falloff * falloff * gradient;
	//blend all vertices' contribution
	vec3 w;
	w.x = 50.1;
	w.y = 50.1;
	w.z = 50.7;
	return dot(n, w);
}



Inline vec3 f_perlin2DNoise(in vec2 uv, bool revert) {
	vec2 i = floor(uv);
	vec2 f = fract(uv);


	// quintic interpolation
	vec2 u = f * f * f * (f * (f * 6.0 - 15.0) + 10.0);
	vec2 du = f * f * 30.0f * (f * (f - 2.0) + 1.0);

	vec2 a; a.x = 0; a.y = 0;
	vec2 b; b.x = 1; b.y = 0;
	vec2 c; c.x = 0; c.y = 1;
	vec2 d; d.x = 1; d.y = 1;
	//random gradients
	vec2 ga = random(i + a);
	vec2 gb = random(i + b);
	vec2 gc = random(i + c);
	vec2 gd = random(i + d);

	//random values by random gradients
	float va = dot(ga, f - a);
	float vb = dot(gb, f - b);
	float vc = dot(gc, f - c);
	float vd = dot(gd, f - d);

	//mix(mix(va, vb, u.x), mix(vc, vd, u.x), u.y);
	float value = va + u.x * (vb - va) + u.y * (vc - va) + u.x * u.y * (va - vb - vc + vd);

	vec2 vb_vc; vb_vc.x = vb; vb_vc.y = vc;
	//mix(mix(ga, gb, u.x), mix(gc, gd, u.x), u.y);
	vec2 u_yx; u_yx.y = u.x; u_yx.x = u.y;
	vec2 derivatives = ga + (gb - ga) * u.x  + (gc - ga) * u.y  + (ga - gb - gc + gd) * u.x * u.y + du * (u_yx * (va - vb - vc + vd) + vb_vc - va);

	if (revert) value = 1.0 - 2.0 * value;

	vec3 R;
	R.x = value;
	R.y = derivatives.x;
	R.z = derivatives.y;
	return R;
}


/*vec3 f_noise3D(vec3 uv) {
	vec3 i = floor(uv);
	vec3 f = fract(uv);

	vec3 u = f*f*(3.0f-2.0f*f);
	

	vec3 v0; v0.x = 0; v0.y = 0; v0.y = 0;
	vec3 vx; vx.x = 1; vx.y = 0; vx.z = 0;

	vec3 vy; vy.x = 0; v0.y = 1; v0.y = 0;
	vec3 vz; vz.x = 0; vz.y = 0; vz.z = 1;
	vec3 vxy; vxy.x = 1; vxy.y = 1; vxy.z = 1;
	vec3 vxyz; vxyz.x = 1; vxyz.y = 1; vxyz.z = 1;


	vec3 t = mix(
		mix(dot(random(i + v0), f - v0), dot(random(i + vx), f - vx), u.x), 
		mix(dot(random(i + vx), f - vx), dot(random(i + vxy), f - vxy), u.y), 
		mix(dot(random(i + vz), f - vz), dot(random(i + vxyz), f - vxyz), u.z)
	);

	return t;
}*/




#undef in
#undef out

#endif //NOISE






